package spring.fox.config;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.PropertyResolver;
import org.springframework.util.ObjectUtils;

import java.lang.annotation.Annotation;
import java.util.*;

import static java.lang.String.valueOf;
import static org.springframework.core.annotation.AnnotationUtils.getDefaultValue;
import static org.springframework.util.StringUtils.trimWhitespace;

/**
 * @author cuichao
 * @Description: RpcPropertyValues
 * @Date: create in 2021/3/16 14:23
 */
public class RpcPropertyValues implements PropertyValues {

    private PropertyValues source;

    private Annotation annotation;

    private final PropertyResolver propertyResolver;

    private final boolean isIgnore;

    private String[] ignoreAttributeNames;


    public RpcPropertyValues(Annotation annotation, PropertyResolver propertyResolver) {
        this(annotation, propertyResolver, false, new String[0]);
    }

    public RpcPropertyValues(Annotation annotation, PropertyResolver propertyResolver, boolean isIgnore, String[] ignoreAttributeNames) {
        this.isIgnore = isIgnore;
        this.annotation = annotation;
        this.propertyResolver = propertyResolver;
        this.ignoreAttributeNames = ignoreAttributeNames;
        this.source = new MutablePropertyValues(getPropertyAttribute());
    }


    /**
     * 获取注解中的属性配置
     *
     * @return
     */
    private Map<String, Object> getPropertyAttribute() {

        Set<String> ignoreAttributeNamesSet = new HashSet<>(Arrays.asList(ignoreAttributeNames));

        Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);

        Map<String, Object> actualAttributes = new LinkedHashMap<String, Object>();

        for (Map.Entry<String, Object> entry : attributes.entrySet()) {

            String attributeName = entry.getKey();
            Object attributeValue = entry.getValue();
            // 除去注解
            if (attributeValue.getClass().isAnnotation()) {
                continue;
            }
            if (attributeValue.getClass().isArray() && attributeValue.getClass().getComponentType().isAnnotation()) {
                continue;
            }
            //除去默认值
            if (ObjectUtils.nullSafeEquals(attributeValue, getDefaultValue(annotation, attributeName))) {
                continue;
            }
            //除去忽略的值
            if (isIgnore && ignoreAttributeNamesSet.contains(attributeName)) {
                continue;
            }
            //如果值为字符串则SPEL表达式解析
            if (attributeValue instanceof String) {
                attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver);
            } else if (attributeValue instanceof String[]) {
                String[] values = (String[]) attributeValue;
                for (int i = 0; i < values.length; i++) {
                    values[i] = resolvePlaceholders(values[i], propertyResolver);
                }
                attributeValue = values;
            }
            actualAttributes.put(attributeName, attributeValue);
        }
        return actualAttributes;

    }


    private String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) {
        String resolvedValue = attributeValue;
        if (propertyResolver != null) {
            resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue);
            resolvedValue = trimWhitespace(resolvedValue);
        }
        return resolvedValue;
    }

    @Override
    public PropertyValue[] getPropertyValues() {
        return source.getPropertyValues();
    }

    @Override
    public PropertyValue getPropertyValue(String propertyName) {
        return source.getPropertyValue(propertyName);
    }

    @Override
    public PropertyValues changesSince(PropertyValues old) {
        return source.changesSince(old);
    }

    @Override
    public boolean contains(String propertyName) {
        return source.contains(propertyName);
    }

    @Override
    public boolean isEmpty() {
        return source.isEmpty();
    }
}
